home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 2008 April
/
PCWorld_2008-04_cd.bin
/
v cisle
/
personasfirefox
/
personas-latest.xpi
/
chrome
/
personas.jar
/
content
/
personas.js
< prev
next >
Wrap
Text File
|
2008-01-09
|
18KB
|
502 lines
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Personas.
*
* The Initial Developer of the Original Code is Mozilla.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Beard <cbeard@mozilla.org>
* Myk Melez <myk@mozilla.org>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const PERSONAS_VERSION = "0.9.1";
let PersonaController = {
_defaultToolbarBackgroundImage: null,
_defaultStatusbarBackgroundImage: null,
//**************************************************************************//
// Shortcuts
// Preference Service
get _prefSvc() {
let prefSvc = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
prefSvc.QueryInterface(Ci.nsIPrefBranch2);
delete this._prefSvc;
this._prefSvc = prefSvc;
return this._prefSvc;
},
// Persona Service
get _personaSvc() {
let personaSvc = Cc["@mozilla.org/personas/persona-service;1"].
getService(Ci.nsIPersonaService);
delete this._personaSvc;
this._personaSvc = personaSvc;
return this._personaSvc;
},
get _stringBundle() {
let stringBundle = document.getElementById("personasStringBundle");
delete this._stringBundle;
this._stringBundle = stringBundle;
return this._stringBundle;
},
get _menu() {
let menu = document.getElementById("personas-selector-menu");
delete this._menu;
this._menu = menu;
return this._menu;
},
/**
* Get the value of a pref, if any; otherwise, get the default value.
*
* @param prefName
* @param defaultValue
* @returns the value of the pref, if any; otherwise, the default value
*/
_getPref: function(prefName, defaultValue) {
let prefSvc = this._prefSvc;
try {
switch (prefSvc.getPrefType(prefName)) {
case Ci.nsIPrefBranch.PREF_STRING:
return prefSvc.getCharPref(prefName);
case Ci.nsIPrefBranch.PREF_INT:
return prefSvc.getIntPref(prefName);
case Ci.nsIPrefBranch.PREF_BOOL:
return prefSvc.getBoolPref(prefName);
}
}
catch (ex) {}
return defaultValue;
},
// FIXME: for performance, make this a memoizing getter with a pref listener
// that updates it as the pref changes.
get _currentPersona() {
return this._getPref("extensions.personas.selected", "default");
},
get _baseURL() {
return this._getPref("extensions.personas.url");
},
get _locale() {
switch (this._getPref("general.useragent.locale", "en-US")) {
case 'ja':
case 'ja-JP-mac':
return "ja";
}
return "en-US";
},
//**************************************************************************//
// Initialization
startUp: function() {
// Get the persona service to ensure it gets initialized and starts updating
// the lists of categories and personas on a regular basis.
Cc["@mozilla.org/personas/persona-service;1"].getService();
// Record the default toolbar and statusbar background images so we can
// revert to them if the user selects the default persona.
let toolbar = document.getElementById("main-window");
this._defaultToolbarBackgroundImage = toolbar.style.backgroundImage;
let statusbar = document.getElementById("status-bar");
if (statusbar)
this._defaultStatusbarBackgroundImage = statusbar.style.backgroundImage;
// Check for a first run or updated extension and display some additional
// information to users.
let firstRun = this._getPref("extensions.personas.lastversion");
if (firstRun == "firstrun") {
let firstRunURL = this._baseURL + this._locale + "/firstrun/?version=" + PERSONAS_VERSION;
setTimeout(function() { window.openUILinkIn(firstRunURL, "tab") }, 500);
this._prefSvc.setCharPref("extensions.personas.lastversion", PERSONAS_VERSION);
}
else if (firstRun != PERSONAS_VERSION) {
let updatedURL = this._baseURL + this._locale + "/updated/?version=" + PERSONAS_VERSION;
setTimeout(function() { window.openUILinkIn(updatedURL, "tab") }, 500);
this._prefSvc.setCharPref("extensions.personas.lastversion", PERSONAS_VERSION);
}
// Apply the current persona to the browser theme.
this._updateTheme();
// Observe changes to the selected persona that happen in other windows
// or by users twiddling the preferences directly.
this._prefSvc.addObserver("extensions.personas.", this, false);
},
shutDown: function() {
this._prefSvc.removeObserver("extensions.personas.", this);
},
// nsISupports
QueryInterface: function(aIID) {
if (aIID == Ci.nsIObserver || aIID == Ci.nsISupports)
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
},
// nsIObserver
observe: function(subject, topic, data) {
switch (topic) {
case "nsPref:changed":
switch (data) {
case "extensions.personas.selected":
case "extensions.personas.manualPath":
case "extensions.personas.category":
this._updateTheme();
break;
}
break;
}
},
/**
* Set the current persona to the one with the specified ID.
*
* @param personaID the ID of the persona to set as the current one.
*/
_setPersona: function(personaID, categoryID) {
// Update the list of recent personas.
if (personaID != "default" && personaID != this._currentPersona && this._currentPersona != "random") {
this._prefSvc.setCharPref("extensions.personas.lastselected2",
this._getPref("extensions.personas.lastselected1"));
this._prefSvc.setCharPref("extensions.personas.lastselected1",
this._getPref("extensions.personas.lastselected0"));
this._prefSvc.setCharPref("extensions.personas.lastselected0", this._currentPersona);
}
// Save the new selection to prefs.
//this._prefSvc.setBoolPref("extensions.personas.selectedIsDark", dark);
this._prefSvc.setCharPref("extensions.personas.selected", personaID);
this._prefSvc.setCharPref("extensions.personas.category", categoryID);
},
_getDarkPropertyByPersona: function(personaID) {
// FIXME: temporary hack to get around slow loading on initialization
if (!this._personaSvc.personas)
return false;
let personas = this._personaSvc.personas.wrappedJSObject;
for each (let persona in personas)
if (persona.id == personaID)
return typeof persona.dark != "undefined" && persona.dark == "true";
return false;
},
_getRandomPersonaByCategory: function(currentPersona, categoryID) {
let personas = this._personaSvc.personas.wrappedJSObject;
let subList = new Array();
let k = 0;
// Build the list of possible personas to select from
for each (let persona in personas) {
let needle = categoryID;
let haystack = persona.menu;
if (haystack.search(needle) == -1)
continue;
subList[k++] = persona;
}
// Get a random item, trying up to five times to get one that is different
// from the currently-selected item in the category (if any).
// We use Math.floor instead of Math.round to pick a random number because
// the JS reference says Math.round returns a non-uniform distribution
// <http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Math:random#Examples>.
let randomIndex, randomItem;
for (let i = 0; i < 5; i++) {
randomIndex = Math.floor(Math.random() * subList.length);
randomItem = subList[randomIndex];
if (randomItem.id != currentPersona)
break;
}
return randomItem.id;
},
// FIXME: update the menu item to display the persona name as its label.
_updateTheme: function() {
let personaID = this._getPref("extensions.personas.selected") || "default";
// If a random persona has been selected, pick the next one from the category.
// First check to ensure that the personas list has been updated by the service,
// as this sometimes doesn't work on startup if your network connection is slow.
if (personaID == "random") {
if (this._personaSvc.personas) {
let categoryID = this._getPref("extensions.personas.category");
personaID = this._getRandomPersonaByCategory(personaID, categoryID);
this._prefSvc.setCharPref("extensions.personas.lastrandom", personaID);
}
else
personaID = this._getPref("extensions.personas.lastrandom");
}
if (personaID == "default")
this._applyDefault();
else
this._applyPersona(personaID);
},
_applyDefault: function() {
let toolbar = document.getElementById("main-window");
toolbar.removeAttribute("persona");
toolbar.style.backgroundImage = this._defaultToolbarBackgroundImage;
toolbar.removeAttribute("_personas-dark-style");
let statusbar = document.getElementById("status-bar");
if (statusbar) {
statusbar.removeAttribute("persona");
statusbar.style.backgroundImage = this._defaultStatusbarBackgroundImage;
}
},
_applyPersona: function(personaID) {
let isDark = this._getDarkPropertyByPersona(personaID);
// Style the primary toolbar box, adding the background image and changing
// the text color to reflect dark vs. light personas as advertised by the feed.
let toolbar = document.getElementById("main-window");
toolbar.setAttribute("persona", personaID);
toolbar.style.backgroundImage = "url('" + this._getToolbarURL(personaID) + "')";
toolbar.setAttribute("_personas-dark-style", isDark ? "true" : "");
// Style the statusbar, adding the background image.
let statusbar = document.getElementById("status-bar");
if (statusbar) {
statusbar.setAttribute("persona", personaID);
statusbar.style.backgroundImage = "url('" + this._getStatusbarURL(personaID) + "')";
}
},
_getToolbarURL: function(personaID) {
switch (personaID) {
case "default":
return "chrome://personas/skin/default/tbox-default.jpg";
case "manual":
return "file://" + this._prefSvc.getCharPref("extensions.personas.manualPath");
}
return this._baseURL + "skins/" + personaID + "/tbox-" + personaID + ".jpg";
},
_getStatusbarURL: function(personaID) {
if (personaID == "default")
return "chrome://personas/skin/default/stbar-default.jpg";
return this._baseURL + "skins/" + personaID + "/stbar-" + personaID + ".jpg";
},
onPersonaPopupShowing: function(event) {
if (event.target != this._menu)
return;
let categories = this._personaSvc.categories.wrappedJSObject;
let personas = this._personaSvc.personas.wrappedJSObject;
this._rebuildMenu(categories, personas);
},
_getCategoryName: function(categoryID) {
let categories = this._personaSvc.categories.wrappedJSObject;
for each (let category in categories)
if (category.id == categoryID)
return category.label;
return "(unknown)";
},
_getPersonaName: function(personaID) {
let personas = this._personaSvc.personas.wrappedJSObject;
let defaultString = this._stringBundle.getString("Default");
if (personaID == "default")
return defaultString;
for each (let persona in personas)
if (persona.id == personaID)
return persona.label;
return defaultString;
},
_rebuildMenu: function(categories, personas) {
let openingSeparator = document.getElementById("personasOpeningSeparator");
let closingSeparator = document.getElementById("personasClosingSeparator");
// Remove everything between the two separators.
while (openingSeparator.nextSibling && openingSeparator.nextSibling != closingSeparator)
this._menu.removeChild(openingSeparator.nextSibling);
//document.getElementById("personas-default").disabled = (this.currentPersona == "default");
let personaStatus = document.getElementById("persona-current");
if (this._currentPersona == "random") {
personaStatus.setAttribute("class", "menuitem-iconic");
personaStatus.setAttribute("image", "chrome://personas/skin/random-feed-16x16.png");
personaStatus.setAttribute("label", this._stringBundle.getString("useRandomPersona.label") + " " +
this._getCategoryName(this._getPref("extensions.personas.category")) + " : " +
this._getPersonaName(this._getPref("extensions.personas.lastrandom")));
}
else {
personaStatus.removeAttribute("class");
personaStatus.removeAttribute("image");
personaStatus.setAttribute("label", this._getPersonaName(this._currentPersona));
}
document.getElementById("personas-manual-separator").hidden =
document.getElementById("personas-manual").hidden =
(this._getPref("extensions.personas.editor") != "manual");
for each (let category in categories) {
let menu = document.createElement("menu");
menu.setAttribute("label", category.label);
let popupmenu = document.createElement("menupopup");
popupmenu.setAttribute("id", category.id);
switch (category.type) {
case "list":
for each (let persona in personas) {
let needle = category.id;
let haystack = persona.menu;
if (haystack.search(needle) == -1)
continue;
let item = this._createPersonaItem(persona, category.id);
popupmenu.appendChild(item);
}
// Create an item that picks a random persona from the category.
popupmenu.appendChild(document.createElement("menuseparator"));
let (item = document.createElement("menuitem")) {
item.setAttribute("personaid", "random");
item.setAttribute("categoryid", category.id);
item.setAttribute("class", "menuitem-iconic");
item.setAttribute("image", "chrome://personas/skin/random-feed-16x16.png");
item.setAttribute("label", this._stringBundle.getString("useRandomPersona.label") + " " + category.label);
item.setAttribute("oncommand", "PersonaController.onSelectPersona(event.target);");
popupmenu.appendChild(item);
}
break;
case "recent":
for (let i = 0; i < 3; i++) {
let recentID = this._getPref("extensions.personas.lastselected" + i);
if (!recentID)
continue;
// Find the persona whose ID matches the one in the preference.
for each (let persona in personas) {
if (persona.id == recentID) {
let item = this._createPersonaItem(persona, "");
popupmenu.appendChild(item);
break;
}
}
}
break;
}
menu.appendChild(popupmenu);
if (category.parent == "top")
this._menu.insertBefore(menu, closingSeparator);
else {
let categoryMenu = document.getElementById(category.parent);
categoryMenu.insertBefore(menu, categoryMenu.firstChild);
}
}
},
_createPersonaItem: function(persona, categoryid) {
let item = document.createElement("menuitem");
// We store the ID of the persona in the "personaid" attribute instead of
// the "id" attribute because "id" has to be unique, and personas sometimes
// are associated with multiple menuitems (f.e. one in the Recent menu
// and another in a category menu).
item.setAttribute("personaid", persona.id);
item.setAttribute("label", persona.label);
item.setAttribute("type", "checkbox");
item.setAttribute("checked", (persona.id == this._currentPersona));
item.setAttribute("autocheck", "false");
item.setAttribute("categoryid", categoryid);
item.setAttribute("oncommand", "PersonaController.onSelectPersona(event.target);");
return item;
},
onSelectPersona: function(menuitem) {
let personaID = menuitem.getAttribute("personaid");
let categoryID = menuitem.getAttribute("categoryid");
this._setPersona(personaID, categoryID);
},
onSelectDefault: function() {
this._setPersona("default", "");
},
onSelectManual: function(event) {
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, "Select a File", Ci.nsIFilePicker.modeOpen);
let result = fp.show();
if (result == Ci.nsIFilePicker.returnOK) {
this._prefSvc.setCharPref("extensions.personas.manualPath", fp.file.path);
this._setPersona("manual", "");
}
},
onSelectAbout: function(event) {
window.openUILinkIn(this._baseURL + this._locale + "/about/?persona=" + this._currentPersona, "tab");
}
};
window.addEventListener("load", function(e) { PersonaController.startUp(e); }, false);
window.addEventListener("unload", function(e) { PersonaController.shutDown(e); }, false);